package kr.jobseeker.movinavi;


import static com.google.android.gms.maps.GoogleMap.MAP_TYPE_NORMAL;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener;
import com.google.android.gms.maps.SupportMapFragment;


import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

/**
 * @author Administrator
 *
 */
public class MapHandling extends FragmentActivity {

	
	public static LatLng DEFAULT_GP = new LatLng(37.566500, 126.978000);// 서울

	// Minimum & maximum latitude so we can span it
	// The latitude is clamped between -80 degrees and +80 degrees inclusive
	// thus we ensure that we go beyond that number
	private double minLatitude =  +81;
	private double maxLatitude =  -81;

	// Minimum & maximum longitude so we can span it
	// The longitude is clamped between -180 degrees and +180 degrees inclusive
	// thus we ensure that we go beyond that number
	private double minLongitude = +181;
	private double maxLongitude = -181;

	protected GoogleMap mMap;
	private ProgressDialog progressDialog;
	private String errorString = "";
	private MapUtility httpUtil;
	private AlertDialog errorDialog;
	
	private String STA_LOC = "";	// 길찾기용 변수
	private String END_LOC = "";
	
	private ImageButton searchBt;
	private FrameLayout under_layout;
	private TextView tv;
	private Button next;
	private Button before;
	private ArrayList<Marker> marker;	// 지도 위의 모든 마커를 저장
	private int marker_position;	// 현재 가리키고 있는 마커의 위치
    private String theaterName = "";
    private String restName = "";
    private TheaterInfo theater = null;
    private RestaurantInfo restaurant = null;
    private String TYPE = ""; 	// theater: true, restaurant: false
    
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		setTitle("MoviNavi");

		setUpMapIfNeeded();
		
		searchBt = (ImageButton) findViewById(R.id.mapview_searchBt);
		searchBt.setVisibility(View.VISIBLE);
		searchBt.setOnClickListener(onNameSearch);
		
		Intent intent1 = getIntent();
		TYPE = intent1.getStringExtra("type"); // theater: true, restaurant: false

		
		// httpUtil
		httpUtil = new MapUtility();

		// 아래 레이아웃에 정보 표시
		under_layout = (FrameLayout)findViewById(R.id.framelayout_bottom);    
		under_layout.setBackgroundColor(Color.argb(200, 157, 207, 255));
		under_layout.setVisibility(FrameLayout.INVISIBLE);
		
		tv = (TextView)findViewById(R.id.textView1);

		next = (Button)findViewById(R.id.next_button);
		before = (Button)findViewById(R.id.before_button);
		next.setOnClickListener(nextBtn);
		before.setOnClickListener(beforeBtn);
		
		
		errorDialog = new AlertDialog.Builder(this).setTitle("오류")
				.setMessage(errorString).setPositiveButton("확인", null)
				.create();
		
		marker = new ArrayList<Marker>();
		marker_position = 0;
				
		markerClicked();
	
	}
	
	// 다음 marker로 이동
	private View.OnClickListener nextBtn = new View.OnClickListener() {
		@Override
		public void onClick(View arg0) {
			marker_position = marker_position % marker.size();
			
			marker.get(marker_position).showInfoWindow();
			mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(marker.get(marker_position).getPosition() , 18));
			Toast.makeText(getApplicationContext(), Integer.toString(marker_position), Toast.LENGTH_SHORT).show();
			
			if(marker_position < marker.size()-1)
				marker_position++;	
		}
	};

	// 이전 marker로 이동
	private View.OnClickListener beforeBtn = new View.OnClickListener() {
			@Override
			public void onClick(View arg0) {
				marker.get(marker_position).showInfoWindow();
				mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(marker.get(marker_position).getPosition() , 18)); 
				Toast.makeText(getApplicationContext(), Integer.toString(marker_position), Toast.LENGTH_SHORT).show();
				
				if(marker_position > 0 )
					marker_position--;
			}
		};
	
	private void markerClicked(){
		// 마커 상세정보         
		mMap.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {
			public void onInfoWindowClick(Marker m) {
				END_LOC = m.getTitle();
				theaterName = m.getTitle().substring(0, m.getTitle().indexOf(","));
				if(theaterName.endsWith("점")){
					theaterName = theaterName.substring(0, theaterName.length()-1);
				}
				restName = m.getTitle();
				String menu = "정보";
				if(TYPE.equals("영화관")){
					menu = "상영시간표";
				}else if(TYPE.equals("음식점")){
					menu = "정보";
				}
		        AlertDialog alert2 = new AlertDialog.Builder(MapHandling.this)
                .setTitle(m.getTitle())
                .setMessage("선택?")
                .setNegativeButton(menu,
                      new DialogInterface.OnClickListener() {
                         @Override
                         public void onClick(DialogInterface dialog, int which) {
                        	 if(TYPE.equals("영화관")){ showTheaterInfo();}
                        	 else if(TYPE.equals("음식점")){ showRestInfo();}
                         }         
                	})
				.setPositiveButton("길찾기",
					new DialogInterface.OnClickListener() { 
						public void onClick(DialogInterface dialog, int which) {
							// 이곳에 길찾기 코드 시작
							getDirection(STA_LOC, END_LOC);
						}         
					
					}).show();
			};         
		}); 
	}
	
	private void showRestInfo()
	{
		//파싱해서 정보 저장
        HTMLparserForRest restParser = new HTMLparserForRest();
        try {
           restaurant = restParser.parser(restName);
        } catch (Exception e) {
           e.printStackTrace();
        }


        if(restaurant!=null) {
        	//보여줄 내용 받아옴
            StringBuilder builder = new StringBuilder(); 
            builder.append(restaurant.getInfo() + "\n");
            builder.append(restaurant.getPhone() + "\n");
            builder.append("평가: " + restaurant.getRateAvg() + "\n" + "최근 3개 리뷰\n");
            for(int i=0; i<restaurant.getRate().size(); i++) {
                builder.append(restaurant.getRate().get(i) + "\n");
                builder.append(restaurant.getReview().get(i) + "\n");
            }
        	final AlertDialog.Builder choose_bg = new AlertDialog.Builder(MapHandling.this);
        	choose_bg.setIcon(R.drawable.ic_launcher);
        	choose_bg.setTitle(restaurant.getRestaurant());
        	choose_bg.setMessage(builder.toString());
            choose_bg.setCancelable(true);
            choose_bg.show();
        }else {
        	Toast.makeText(getApplicationContext(), "식당 정보가 없습니다.", Toast.LENGTH_LONG).show();
        }
        
	}
	
	private void showTheaterInfo()
	{
        HTMLparserForTheater test = new HTMLparserForTheater();
        try {
           theater = test.parser(theaterName);
        } catch (Exception e) {
           e.printStackTrace();
        }
        if(theater!=null) {
        	final AlertDialog.Builder choose_bg = new AlertDialog.Builder(MapHandling.this);
        	choose_bg.setIcon(R.drawable.ic_launcher);
        	choose_bg.setTitle(theater.getTheater());
        	final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(
        			MapHandling.this,  android.R.layout.select_dialog_singlechoice);
            
            for(int i=0; i<theater.getMovies().size();i++){
            	arrayAdapter.add(theater.getMovies().get(i) + "\n");
            }
            choose_bg.setAdapter(arrayAdapter,
            		new DialogInterface.OnClickListener() {
            			public void onClick(DialogInterface dialog, int which) {
            				String strName = arrayAdapter.getItem(which);
            				AlertDialog.Builder builderInner = new AlertDialog.Builder(MapHandling.this);
            				builderInner.setIcon(R.drawable.ic_launcher);
            				builderInner.setMessage(theater.getMovies_info().get(which).toString() + "\n\n" + theater.getTimes(which).toString()
            										  .substring(1, theater.getTimes(which).toString().length()-1) + "\n");
            				builderInner.setTitle(strName);
            				builderInner.setNegativeButton("뒤로가기",
                            	new DialogInterface.OnClickListener() {
            						public void onClick(DialogInterface dialog, int which) {
            							choose_bg.show();
            						}
            				});
            				builderInner.show();
            			}
            });
            choose_bg.setCancelable(true);
            choose_bg.show();
            
        }else {
        	Toast.makeText(getApplicationContext(), "영화관 정보가 없습니다.", Toast.LENGTH_LONG).show();
        }
	}
	
	private void getDirection(String start_address, String end_address){
	//  아래 요청은 온타리오, 토론토에서 퀘벡, 몬트리올까지의 운전 경로를 반환합니다.
	//	http://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&sensor=false&avoid=highways&mode=bicycling
	//	mode 및 avoid 매개변수를 변경하여 주요 고속도로를 피해 경치가 좋은 자전거 경로 길찾기를 반환하도록 초기 요청을 수정할 수 있습니다.
	//		http://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&sensor=false&avoid=highways&mode=bicycling
		if (progressDialog != null && progressDialog.isShowing())
			return;
		progressDialog = ProgressDialog.show( MapHandling.this, "Wait", "경로를 탐색 중입니다");

		String start_addr = start_address;
		String end_addr = end_address;
		
//		httpUtil.requestGetDirection(new ResultHandler_d(MainActivity.this), "37.561061,126.978071", "37.545139,126.972148");
		httpUtil.requestGetDirection(new ResultHandler_d(MapHandling.this), start_addr, end_addr);

	
	}
	
	// 지도에 길찾기 결과를 뿌려준다.
	private void showDirection(ArrayList<DirInfo> info, final ArrayList<Steps> step)
	{
		// dirInfoList : distance, duration, end_location_lat, end_location_lng, start_location_lat, start_location_lng 
		// dirStepList: distance, duration, end_location_lat, end_location_lng, 
		//				html_instructions, start_location_lat, start_location_lng, travel_mode 
		mMap.clear();
		marker.clear();

		under_layout.setVisibility(FrameLayout.VISIBLE);
		tv = (TextView)findViewById(R.id.textView1);
		tv.setText( 
				"이동경로 요약" + "\n" +
				"거리: "+ info.get(0).getDistance() + "\n" +
				"시간: "+ info.get(0).getDuration() + "\n" +
				"출발지: " + getAddres(
						Double.valueOf(  info.get(0).getStart_location_lat()  ),
						Double.valueOf(  info.get(0).getStart_location_lng() )
						)+"\n" +
				"도착지: " + getAddres(
						Double.valueOf(  info.get(0).getEnd_location_lat()  ),
						Double.valueOf(  info.get(0).getEnd_location_lng() )
						)
				);

	
		// 중간 이동과정 마커 추가
	
		LatLng sPoints;	// start
		LatLng ePoints;	// end
		
		int length = step.size();
		LatLng[] mPoints = new LatLng[length];
		
		for (int i = 0; i < length; i++) {
			sPoints =  new LatLng(
					Float.valueOf(step.get(i).getStart_location_lat()),
					Float.valueOf(step.get(i).getStart_location_lng()));
			ePoints = new LatLng(
					Float.valueOf(step.get(i).getEnd_location_lat()),
            		Float.valueOf(step.get(i).getEnd_location_lng()));

			// marker 추가
			marker.add( 
				mMap.addMarker(new MarkerOptions()
				    .position(sPoints)
				    .title(getAddres(
							Double.valueOf(  step.get(i).getStart_location_lat()  ),
							Double.valueOf(  step.get(i).getStart_location_lng() )
							))
				    .snippet( "거리: "+step.get(i).getDistance()+ "\n" +
				    		"시간: "+step.get(i).getDuration()+ "\n" +
				    		step.get(i).getHtml_instructions())
			    )
		    );
			
			Polyline line = mMap.addPolyline(new PolylineOptions()
		     .add(sPoints, ePoints)
		     .width(5)
		     .color(Color.RED));
			
		}
		
		// 도착지 마커 추가
		
		marker.add(
				mMap.addMarker(new MarkerOptions()
			    .position( new LatLng(  Double.valueOf(info.get(0).getEnd_location_lat()),
			    						Double.valueOf(info.get(0).getEnd_location_lng() ) ))			    
			    .title("도착: "+ getAddres(
						Double.valueOf(  step.get(0).getEnd_location_lat()  ),
						Double.valueOf(  step.get(0).getEnd_location_lng() )
						))
			    )
		);
		CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(new LatLngBounds(new LatLng(minLatitude, minLongitude), new LatLng(maxLatitude, maxLongitude)), 4);
		mMap.animateCamera(cu);
		
		
	}
	
	private void setUpMapIfNeeded() {
        if (mMap == null) {
            mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
            if (mMap != null) {
                setUpMap();
            }
        }
    }

	private void setUpMap() {
		Log.d("dd", "setUpMap");
		mMap.setMapType(MAP_TYPE_NORMAL);
		mMap.setMyLocationEnabled(true);
		
	}

	private View.OnClickListener onNameSearch = new View.OnClickListener() {
		public void onClick(View arg0){
			getCurrentLocation();
		}		
	};
	public void getCurrentLocation() {
			Location lo = mMap.getMyLocation();
			STA_LOC = getAddres(lo.getLatitude(), lo.getLongitude());
			searchPlaces(TYPE, STA_LOC);
	}

	public void searchPlaces(String type, String sta_loc) {
			
				if (progressDialog != null && progressDialog.isShowing())
					return;
				progressDialog = ProgressDialog.show( MapHandling.this, "Wait", "검색 중입니다");
				Log.d("결과", type);
				httpUtil.requestMapSearch(new ResultHandler(MapHandling.this), type, sta_loc);
	}
	
	static class ResultHandler extends Handler {
		private final WeakReference<MapHandling> mActivity;
		
		ResultHandler(MapHandling activity) {
			mActivity = new WeakReference<MapHandling>(activity);
		}
		
		@Override
		public void handleMessage(Message msg) {
			MapHandling activity = mActivity.get();
			if(activity != null) {
				activity.handleMessage(msg);
			}
		}
	}
	
	static class ResultHandler_d extends Handler {
		private final WeakReference<MapHandling> mActivity;
		
		ResultHandler_d(MapHandling activity) {
			mActivity = new WeakReference<MapHandling>(activity);
		}
		
		@Override
		public void handleMessage(Message msg) {
			MapHandling activity = mActivity.get();
			if(activity != null) {
				activity.handleMessage_d(msg);
			}
		}
	}
	
	private void handleMessage_d(Message msg) {
		progressDialog.dismiss();

		String result = msg.getData().getString(MapUtility.RESULT);
		ArrayList<DirInfo> dirInfoList = new ArrayList<DirInfo>();
		ArrayList<Steps> dirStepList = new ArrayList<Steps>();
		

		if (result.equals(MapUtility.SUCCESS_RESULT)) {
			dirInfoList = msg.getData().getParcelableArrayList("dirInfoList");
			dirStepList = msg.getData().getParcelableArrayList("dirStepList");
		} else if (result.equals(MapUtility.TIMEOUT_RESULT)) {
			errorString = "네트워크 연결이 안됩니다.";
			errorDialog.setMessage(errorString);
			errorDialog.show();
			return;
		} else if (result.equals(MapUtility.FAIL_MAP_RESULT)) {
			errorString = "길찾기가 안됩니다.";
			errorDialog.setMessage(errorString);
			errorDialog.show();
			return;
		} else {
			errorString = httpUtil.stringData;
			errorDialog.setMessage(errorString);
			errorDialog.show();
			return;
		}
		
		Toast.makeText(this, "Success !!!", Toast.LENGTH_SHORT).show();
		showDirection(dirInfoList, dirStepList);
	}
	
	private void handleMessage(Message msg) {
		progressDialog.dismiss();

		String result = msg.getData().getString(MapUtility.RESULT);
		ArrayList<String> searchList = new ArrayList<String>();

		if (result.equals(MapUtility.SUCCESS_RESULT)) {
			searchList = msg.getData().getStringArrayList("searchList");

		} else if (result.equals(MapUtility.TIMEOUT_RESULT)) {
			errorString = "네트워크 연결이 안됩니다.";
			errorDialog.setMessage(errorString);
			errorDialog.show();
			return;
		} else if (result.equals(MapUtility.FAIL_MAP_RESULT)) {
			errorString = "검색이 안됩니다.";
			errorDialog.setMessage(errorString);
			errorDialog.show();
			return;
		} else {
			errorString = httpUtil.stringData;
			errorDialog.setMessage(errorString);
			errorDialog.show();
			return;
		}
		
		Toast.makeText(this, "Success !!!", Toast.LENGTH_SHORT).show();

		String[] searches = searchList.toArray(new String[searchList.size()]);
		adjustToPoints(searches);
	}

	/**
	 * 주어진 위치들에 적합한 줌, 이동시킴
	 * 
	 * @param mPoints
	 */
	protected void adjustToPoints(String[] results) {
		
		mMap.clear();
		
		int length = Integer.valueOf(results.length / 3);
		LatLng[] mPoints = new LatLng[length];
		
		for (int i = 0; i < length; i++) {
			LatLng latlng = new LatLng(
            		Float.valueOf(results[i * 3 + 1]),
            		Float.valueOf(results[i * 3 + 2]));
            // 마커의 info window
			mMap.addMarker(new MarkerOptions()
                    .position(latlng)
                    .title(results[i * 3])
                    .icon(BitmapDescriptorFactory.defaultMarker(i * 360 / length)));
            mPoints[i] = latlng;
        }
		
		for (LatLng ll : mPoints) {

			// Sometimes the longitude or latitude gathering
			// did not work so skipping the point
			// doubt anybody would be at 0 0
			if (ll.latitude != 0 && ll.longitude != 0) {
				// Sets the minimum and maximum latitude so we can span and zoom
				minLatitude = (minLatitude > ll.latitude) ? ll.latitude : minLatitude;
				maxLatitude = (maxLatitude < ll.latitude) ? ll.latitude : maxLatitude;
				// Sets the minimum and maximum latitude so we can span and zoom
				minLongitude = (minLongitude > ll.longitude) ? ll.longitude	: minLongitude;
				maxLongitude = (maxLongitude < ll.longitude) ? ll.longitude	: maxLongitude;
			}
		}
		
		Log.d("dd", minLatitude + "/" +maxLatitude + "/"+minLongitude + "/"+maxLongitude);
		
		CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(new LatLngBounds(new LatLng(minLatitude, minLongitude), new LatLng(maxLatitude, maxLongitude)), 4);
		mMap.animateCamera(cu);
		
	}

	@Override
	public void onResume() {
		super.onResume();
        setUpMapIfNeeded();
	}
	
	private String getAddres(double lat, double lng) {
		Geocoder gcK = new Geocoder(getApplicationContext(), Locale.KOREA);
		String res = "서울특별시 동대문구 서울시립대학교";
		try {
			List<Address> addresses = gcK.getFromLocation(lat, lng, 1);
			StringBuilder sb = new StringBuilder();

			if (null != addresses && addresses.size() > 0) {
				Address address = addresses.get(0);
				// sb.append(address.getCountryName()).append("/");
				// sb.append(address.getPostalCode()).append("/");
				sb.append(address.getLocality()).append(" ");
				sb.append(address.getThoroughfare()).append(" ");
				sb.append(address.getFeatureName());
				res = sb.toString();
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
		return res;
	}
}
